//
// Created by shaowenhan on 2020/3/1.
//

#include "ConfigurableEventListener.h"
#include <algorithm>
#include "../SRC/RandomSequence.h"
class TestRandomSequence: public testing::Test{
public:
    RandomSequence<int> randomElements;
    vector<int> elements = {1, 2, 3, 4};
    vector<int> elements2 = {1, 2, 3};
    vector<int> anotherElements = {5, 6, 7};
    vector<int> eleUsedTime = {0, 0, 0, 0};
    void ASSERT_IN(vector<int> elements, int ele)
    {
        auto ite = find(elements.begin(), elements.end(), ele);
        ASSERT_TRUE(ite != elements.end());
    }
    void ASSERT_IN(vector<vector<int>> elements, vector<int> ele)
    {
        auto ite = find(elements.begin(), elements.end(), ele);
        ASSERT_TRUE(ite != elements.end());
    }
};
TEST_F(TestRandomSequence, ObtainRandomEleInElements)
{
    randomElements.initialElements(elements);
    vector<int> expectedEles({1, 2, 3, 4});

    auto ele = randomElements.nextEle();

    ASSERT_IN(expectedEles, ele);
}

TEST_F(TestRandomSequence, AfterAllElesHaveBeenObtained)
{
    randomElements.initialElements(elements);

    for(int i = 0; i < elements.size(); i++)
        randomElements.nextEle();

    ASSERT_ANY_THROW(randomElements.nextEle());
}
TEST_F(TestRandomSequence, ObtainAllEles)
{
    randomElements.initialElements(elements);

    for(int i = 0; i < elements.size(); i++)
    {
        auto number = randomElements.nextEle();
        ASSERT_LE(number, 4);
        ASSERT_GE(number, 1);
        eleUsedTime[number-1] += 1;
    }
    for(auto usedTime: eleUsedTime)
        ASSERT_EQ(usedTime, 1);
}
TEST_F(TestRandomSequence, ChangeElementsMidway)
{
    randomElements.initialElements(elements);
    vector<int> expectedEles(anotherElements);

    randomElements.nextEle();
    randomElements.initialElements(anotherElements);
    auto ele = randomElements.nextEle();

    ASSERT_IN(expectedEles, ele);
}
TEST_F(TestRandomSequence, ObtainRemainingStateOfElementsTrue)
{
    randomElements.initialElements(elements);
    bool expectedIsRemaining = true;

    randomElements.nextEle();
    auto isRemaining = randomElements.isRemaining();

    ASSERT_EQ(expectedIsRemaining, isRemaining);
}
TEST_F(TestRandomSequence, ObtainRemainingStateOfElementsFalse)
{
    randomElements.initialElements(elements);
    bool expectedIsRemaining = false;

    for(int i = 0; i < elements.size(); i++)
        randomElements.nextEle();
    auto isRemaining = randomElements.isRemaining();

    ASSERT_EQ(expectedIsRemaining, isRemaining);
}
TEST_F(TestRandomSequence, ArrangeElementsRandomly)
{
    vector<vector<int>> expectedAllElements({{1,2,3}, {1,3,2},
                                             {2,1,3}, {2,3,1},
                                             {3,1,2}, {3,2,1}});

    auto elements = randomElements.randomArrangeElements(elements2);

    ASSERT_IN(expectedAllElements, elements);
}
TEST_F(TestRandomSequence, GenerateRandomSequenceWithElementsFromLowerBoundToUpperBound)
{
    vector<vector<int>> expectedAllElements({{0, 1, 2}, {0, 2, 1},
                                             {1, 0, 2}, {1, 2, 0},
                                             {2, 0, 1}, {2, 1, 0}});
    int lower = 0, upper = 2;

    auto elements = randomElements.generateRandomSequenceWithElesFromLowerToUpper(lower, upper);

    ASSERT_IN(expectedAllElements, elements);
}
TEST_F(TestRandomSequence, GenerateRandomSequenceWithElementsFromLowerBoundToUpperBoundWithInterval2)
{
    vector<vector<int>> expectedAllElements({{0, 2}, {2, 0}});

    int lower = 0, upper = 2, interval = 2;

    auto elements = randomElements.generateRandomSequenceWithElesFromLowerToUpper(lower, upper, interval);

    ASSERT_IN(expectedAllElements, elements);
}
